// 类

// 类中有成员属性或者要自定义构造逻辑时, 构造函数一定要写, 使用constructor关键字定义
class Person {
    // 类的成员属性
    name: string;
    age: number;

    // 类的构造函数: 成员函数要在类实例化的时候进行赋值就需要给构造函数添加成员属性的参数并赋值
    constructor(name: string, age: number) {
        this.name = name;
        this.age = age;
    }

    // 类中的方法
    eat() {
        console.log('吃吃吃');
    }
}
console.log(JSON.stringify(new Person('张三', 18)));

// 构造函数简写有成员属性形式, 不需要定义成员属性, 只需要在构造函数中定义属性并使用public关键字修饰
class Animal {
    constructor(public name: string, public age: number) { }
}
console.log(JSON.stringify(new Animal('拉不拉猪', 2)));

// 默认类中属性和方法都是public的, 也可以显式指定为public, private, protected, readonly, static, 成员属性简写的方式必须要显示的指定
class Zhangsan {
    public name: string;
    private age: number;
    readonly sex: string;
    protected country: string;
    public static haha: string;
    constructor(name: string, age: number, sex: string, country: string, haha: string) {
        this.name = name;
        this.age = age;
        this.sex = sex;
        this.country = country;
        Zhangsan.haha = haha;
    }
    eat() {
        console.log('吃吃吃');
    }
}

// 私有属性和静态属性不能简写
class Lisi {
    private age: number;
    public static haha: string
    constructor(public name: string, age: number, readonly sex: string, protected country: string, haha: string) {
        this.age = age;
        Lisi.haha = haha;
    }
    eat() {
        console.log(`年龄: ${this.age}, 吃吃吃`);
    }
}
console.log(JSON.stringify(new Lisi('张三', 18, '男', '中国', 'haha')));

// getter/setter: 属性私有的时候获取和设置属性值, 封装属性值, 可以添加自定义的逻辑
class Wangwu {
    private _name: string;
    private _age: number;
    constructor(name: string, age: number) {
        this._name = name;
        this._age = age;
    }
    get name() {
        console.log('name的getter被调用');
        return this._name;
    }
    set name(name: string) {
        console.log('name的setter被调用');
        this._name = name;
    }
    get age() {
        console.log('age的getter被调用');
        return this._age;
    }
    set age(age: number) {
        console.log('age的setter被调用');
        this._age = age;
    }
}
const wangwu = new Wangwu('张三', 18)
console.log('调用setter前: ', JSON.stringify(wangwu));
wangwu.age = 19
wangwu.name = '王五'
console.log('调用setter后: ', JSON.stringify(wangwu));

// 抽象类: 抽象类不能被实例化, 抽象类中可以有抽象方法, 抽象方法没有方法体, 抽象方法必须在抽象类中
abstract class Animal2 {
    abstract eat(): void;
}

class Dog2 extends Animal2 {
    constructor(public name: string, public age: number) {
        super();
    }
    eat() {
        console.log('吃吃吃');
    }
}
function test(animal: Animal2) {
    animal.eat();
}
// 方法的参数是抽象类, 可以传入抽象类的子类
console.log(test(new Dog2('旺财', 2)));